﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using System.Text.RegularExpressions;

// Assembly marked as compliant.
[assembly: CLSCompliantAttribute(true)]

namespace SQLite2CECmd
{
    class Program
    {
        // parameters
        private static bool _wantVerboseReport = false;
        private static bool _forceOverwrite = false;
        private static string _liteDBPath = null;
        private static string _ceDBPath = null;
        private static string _reportPath = null;
        private static string _settingsPath = null;
        private static bool _skipViews = false;
        private static bool _skipTriggers = false;
        private static bool _skipData = false;

        static void Main(string[] args)
        {
            // Parse args. If bad args, show usage and bail.
            if (!ParseArgs(args))
            {
                Console.WriteLine("SQLite2CECmd: Converts SQLite database into SQL Server Compact Edition database.\n\n" +
                    "Usage:\n\n" +
                    "SQLite2CECmd [--v] [--f] [--sv] [--st] [--sd] -i=<input db file> -o=<output db file> [-r=<report file>] [-s=<settings file>]\n\n" +
                    "where\n" +
                    "--v: Produce verbose output report\n" +
                    "--f: Overwrite output database if it already exists\n" +
                    "--sv: skip views i.e. do not convert any views that may exist in the database\n" +
                    "--st: skip triggers i.e. do not convert any triggers that may exist in the database\n" +
                    "--sd: skip data i.e. do not convert any data that may exist in the database\n" +
                    "-i: full path to input database file (SQLite database)\n" +
                    "-o: full path to output database file (SQL CE database)\n" +
                    "-r: full path to output report file\n" +
                    "-s: full path to input settings\n" +
                    "Only the -i and -o parameters are mandatory. Rest of the parameters are optional.\n\n" +
                    "e.g. SQLite2CECmd --f -i=c:\\test\\test.sqlite -o=c:\\test\\test.sdf" 
                    );
                return;
            }

            // Init converter
            SQLite2CELib.Converter converter = new SQLite2CELib.Converter();
            converter.Init(_wantVerboseReport, _forceOverwrite, _liteDBPath, _ceDBPath, _reportPath, _settingsPath, _skipViews, _skipTriggers, _skipData);

            // convert
            converter.Convert();
        }

        private static bool ParseArgs(string[] args)
        {
            Arguments CommandLine = new Arguments(args);

            // first look for mandatory arguments
            if (CommandLine["i"] != null)
                _liteDBPath = CommandLine["i"];
            else
                return false;   

            if (CommandLine["o"] != null)
                _ceDBPath = CommandLine["o"];
            else
                return false;

            // optional arguments

            // verbose report
            if (CommandLine["v"] != null)
                _wantVerboseReport = true;

            // force overwriting of output db
            if (CommandLine["f"] != null)
                _forceOverwrite = true;

            if (CommandLine["sv"] != null)
                _skipViews = true;

            if (CommandLine["st"] != null)
                _skipTriggers = true;

            if (CommandLine["sd"] != null)
                _skipData = true;

            // report path 
            if (CommandLine["r"] != null)
                _reportPath = CommandLine["r"];

            // settings path 
            if (CommandLine["s"] != null)
                _settingsPath = CommandLine["s"];

            return true;
        }
    }

    public class Arguments
    {
        // Variables
        private StringDictionary _argValues;

        // Constructor
        public Arguments(string[] args)
        {
            _argValues = new StringDictionary();
            Regex Spliter = new Regex(@"^-{1,2}|^/|=|:", RegexOptions.IgnoreCase | RegexOptions.Compiled);
            Regex Remover = new Regex(@"^['""]?(.*?)['""]?$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
            string Parameter = null;
            string[] Parts;

            // Valid parameters forms:
            // {-,/,--}param{ ,=,:}((",')value(",'))
            // Examples: 
            // -param1 value1 --param2 /param3:"Test-:-work" /param4=happy -param5 '--=nice=--'

            foreach (string Txt in args)
            {
                // Look for new parameters (-,/ or --) and a possible enclosed value (=,:)
                Parts = Spliter.Split(Txt, 3);

                switch (Parts.Length)
                {
                    // Found a value (for the last parameter found (space separator))
                    case 1:
                        if (Parameter != null)
                        {
                            if (!_argValues.ContainsKey(Parameter))
                            {
                                Parts[0] =
                                    Remover.Replace(Parts[0], "$1");

                                _argValues.Add(Parameter, Parts[0]);
                            }
                            Parameter = null;
                        }
                        // else Error: no parameter waiting for a value (skipped)

                        break;

                    // Found just a parameter
                    case 2:
                        // The last parameter is still waiting. With no value, set it to true.
                        if (Parameter != null)
                        {
                            if (!_argValues.ContainsKey(Parameter))
                                _argValues.Add(Parameter, "true");
                        }

                        Parameter = Parts[1];
                        break;

                    // Parameter with enclosed value
                    case 3:
                        // The last parameter is still waiting. With no value, set it to true.
                        if (Parameter != null)
                        {
                            if (!_argValues.ContainsKey(Parameter))
                                _argValues.Add(Parameter, "true");
                        }

                        Parameter = Parts[1];

                        // Remove possible enclosing characters (",')
                        if (!_argValues.ContainsKey(Parameter))
                        {
                            Parts[2] = Remover.Replace(Parts[2], "$1");
                            _argValues.Add(Parameter, Parts[2]);
                        }

                        Parameter = null;
                        break;
                }
            }

            // In case a parameter is still waiting
            if (Parameter != null)
            {
                if (!_argValues.ContainsKey(Parameter))
                    _argValues.Add(Parameter, "true");
            }
        }

        // Retrieve a parameter value if it exists (overriding C# indexer property)
        public string this[string argName]
        {
            get
            {
                return (_argValues[argName]);
            }
        }
    }
}
